#!/usr/bin/env python

STD_LOAD_RATE = 30
IDLE_THRESHOLD = 10

ENCODING = 'utf-8'

STATUS_CHG_INTERVAL = 60 # Every 10 minutes
ADS_HOST = 'localhost'
ADS_PORT = 6666


import os
import re
import sys
import time
import codecs
import socket

import dictbot


def read_AccountFile():
	accInfo = {}
	for line in codecs.open(ACCOUNT_FILE, encoding=ENCODING).readlines():
		line = line.strip()
		if len(line) > 0 and not line.startswith('#'):	# Not a blank line or a comment
			tokens = line.split(':')
			key = tokens[0].strip().lower()
			value = (':'.join(tokens[1:])).strip()
			if accInfo.has_key(key):
				accInfo[key] += ';' + value
			else:
				accInfo[key] = value
	return accInfo


def save_AccountFile():
	af = codecs.open(ACCOUNT_FILE + '.tmp', 'w', encoding=ENCODING)
	for line in codecs.open(ACCOUNT_FILE, encoding=ENCODING).readlines():
		if len(line) > 0 and not line.startswith('#') :	# Not a blank line or a comment
			if line.find('status') != -1:
				line = re.sub('^(\s*)status(\s*):.*', '\\1status\\2:' + bot.STATUS_MSG, line, re.U)
			if line.find('accept') != -1:
				if bot.acceptUsers:
					line = re.sub('^(\s*)accept(\s*):.*', '\\1accept\\2:1', line, re.U)
				else:
					line = re.sub('^(\s*)accept(\s*):.*', '\\1accept\\2:0', line, re.U)
		af.write(line)
	af.close()
	os.rename(ACCOUNT_FILE + '.tmp', ACCOUNT_FILE)


def balance_ConnectionLoad():
	global MONITOR_INTERVAL, extra_MONITOR_INTERVAL, idleCount, bot

	MONITOR_INTERVAL = MONITOR_INTERVAL + extra_MONITOR_INTERVAL
	bot.loadRate = 1.0 * bot.loadCount / MONITOR_INTERVAL
	bot.queryRate = 1.0 * bot.queryCount / MONITOR_INTERVAL
	bot.sleepTime = (bot.loadCount / STD_LOAD_RATE) - MONITOR_INTERVAL
	if bot.sleepTime > 0.1:
		extra_MONITOR_INTERVAL = MONITOR_INTERVAL
		MONITOR_INTERVAL = max(3, bot.sleepTime)
		# Won't reset counts if there is additional wait for balancing
	else:
		MONITOR_INTERVAL = 30		# No need to check again sooner
		extra_MONITOR_INTERVAL = 0	# No additional time to count in next round
		bot.sleepTime = 0.1			# Minium sleep
		bot.loadCount = 0
		bot.queryCount = 0

		if bot.loadRate > 0:		# System is not idle
			idleCount = 0
		else:						# Possibly indication of crash/disconnection
			idleCount += 1
			print 'MONITOR: idle for %d time(s)' % idleCount
			if idleCount == IDLE_THRESHOLD and bot.exist:	# Restart thread if the bot was found idle for many times
				print 'MONITOR: reconnecting ...'
				bot.exist = False				# Exit looping in the bot thread
				save_AccountFile()
				bot.join()						# Wait until the old thread terminates
				bot = dictbot.DictBot(read_AccountFile())
				bot.start()
			
	print 'MONITOR: load rate %.2f/sec; sleep for %.2f secs; next check at %.2f secs' % (bot.loadRate, bot.sleepTime, MONITOR_INTERVAL)


def change_BotStatus():
	global bot

	print 'MONITOR: acquiring status message ...'
	try:
		ads = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		ads.connect((ADS_HOST, ADS_PORT))
		ads.send(bot.JID)
		ad = ads.recv(256)
		ads.close()
		print ad
		bot.set_StatusMessage(ad)
	except StandardError:
		print 'ERROR: failure to communicate with adserver'
		return




if __name__ == '__main__':

	# Get account file from command-line	
	if len(sys.argv) != 2:
		print 'USAGE: %s [account.txt]' % (sys.argv[0])
		sys.exit(1)

	# Connect to server
	ACCOUNT_FILE = sys.argv[1]
	bot = dictbot.DictBot(read_AccountFile())
	
	# Run the bot and monitor

	bot.start()
	MONITOR_INTERVAL = 10		# This will be adjusted later as the process goes
	extra_MONITOR_INTERVAL = 0	# Initialisation
	idleCount = 0				# Number of times the system is idle
	sinceLastStatusChg = 0
	while bot.exist:
		time.sleep(MONITOR_INTERVAL)
		balance_ConnectionLoad()
		if not bot.autoStatus:
			sinceLastStatusChg += MONITOR_INTERVAL
			if sinceLastStatusChg > STATUS_CHG_INTERVAL:
				sinceLastStatusChg = 0
				change_BotStatus()
		sys.stdout.flush()	# Update log file immediately

	save_AccountFile()
	del bot
